﻿#include "NodeMatrix.h"

#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgGA/GUIEventHandler>
#include <osgDB/ReadFile>
#include <osg/Geode>
#include <osg/ShapeDrawable>

#include <osgUtil/IntersectVisitor>
#include <osg/LineSegment>

#include <iostream>

#define LEFT		1
#define RIGHT		2
#define UP			3
#define DOWN		4
#define FRONT		5
#define BACK		6
#define END			7

extern void ExportBoxNode();
extern osg::ref_ptr<osg::Group> CreateBox();

class MoveSphereEventHandler : public osgGA::GUIEventHandler
{
public:
	MoveSphereEventHandler(NodeMatrix* node) :
		sphere(nullptr),
		position(osg::Vec3d(0,0,0)),
		box(nullptr),
		point(0),
		pop(nullptr)

	{
		if (!node)
		{
			exit(0);
		}
		sphere = node;
	}

	virtual bool handle(osgGA::Event* event, osg::Object* object, osg::NodeVisitor* nv)
	{
		osgGA::GUIEventAdapter* ea = dynamic_cast<osgGA::GUIEventAdapter*>(event);
		switch (ea->getEventType())
		{
		case osgGA::GUIEventAdapter::KEYDOWN:
			{
				switch (ea->getKey())
				{
					case osgGA::GUIEventAdapter::KEY_Left:
					{
						point = LEFT;
						position = sphere->getPosition();
						ChangePosition(osg::Vec3d(position.x() - 20, position.y(), position.z()), position);
					}
					break;
					case osgGA::GUIEventAdapter::KEY_Right:
					{
						point = RIGHT;
						position = sphere->getPosition();
						ChangePosition(osg::Vec3d(position.x() + 20, position.y(), position.z()), position);
					}
					break;
					case osgGA::GUIEventAdapter::KEY_Up:
					{
						point = FRONT;
						position = sphere->getPosition();
						ChangePosition(osg::Vec3d(position.x(), position.y() + 20, position.z()), position);
					}
					break;
					case osgGA::GUIEventAdapter::KEY_Down:
					{
						point = BACK;
						position = sphere->getPosition();
						ChangePosition(osg::Vec3d(position.x(), position.y() - 20, position.z()), position);
					}
					break;
					case osgGA::GUIEventAdapter::KEY_Home:
					{
						point = UP;
						position = sphere->getPosition();
						ChangePosition(osg::Vec3d(position.x(), position.y(), position.z() + 20), position);
					}
					break;
					case osgGA::GUIEventAdapter::KEY_End:
					{
						point = DOWN;
						position = sphere->getPosition();
						ChangePosition(osg::Vec3d(position.x(), position.y(), position.z() - 20), position);
					}
					break;
					default:
						break;
				} // end switch getKey
			}
		break;

		default:
			break;
		} // end switch getEventType

		return false;
	}

	/* 设置碰撞场景 */
	void setNode(osg::Node* node)
	{
		if (!node)
		{
			// 
		}
		box = node;
	}

	/* 移动 */
	void ChangePosition(osg::Vec3d& NewPos, osg::Vec3d& OldPos)
	{
		osg::ref_ptr<osg::LineSegment> ls = new osg::LineSegment();
		osg::ref_ptr<osgUtil::IntersectVisitor> iv = new osgUtil::IntersectVisitor();
		int minX, maxX, minY, maxY, minZ, maxZ;
		switch (point)
		{
			case LEFT:
			{
				ls->set(osg::Vec3d(NewPos.x() - 40, NewPos.y(), NewPos.z()), OldPos);
			}
			break;
			case RIGHT:
			{
				ls->set(osg::Vec3d(NewPos.x() + 40, NewPos.y(), NewPos.z()), OldPos);
			}
			break;
			case FRONT:
			{
				ls->set(osg::Vec3d(NewPos.x(), NewPos.y() + 40, NewPos.z()), OldPos);
			}
			break;
			case BACK:
			{
				ls->set(osg::Vec3d(NewPos.x(), NewPos.y() - 40, NewPos.z()), OldPos);
			}
			break;
			case UP:
			{
				ls->set(osg::Vec3d(NewPos.x(), NewPos.y(), NewPos.z() + 40), OldPos);
			}
			break;
			case DOWN:
			{
				ls->set(osg::Vec3d(NewPos.x(), NewPos.y(), NewPos.z() - 40), OldPos);
			}
			break;
		default:
			break;
		}

		iv->addLineSegment(ls.get());

		box->accept(*(iv.get()));
		if (iv->hits())
		{
			// 看看撞了谁，输出出来
			{
				// 得到HitList
				osgUtil::IntersectVisitor::HitList hitList = iv->getHitList(ls.get());
				osg::NodePath nodePath;
				osgUtil::IntersectVisitor::HitList::iterator iter = hitList.begin();
				osg::Vec3d X;
				minX = iter->getWorldIntersectPoint().x();
				maxX = minX;
				minY = iter->getWorldIntersectPoint().y();
				maxY = minY;
				minZ = iter->getWorldIntersectPoint().z();
				maxZ = minZ;

				for (; iter != hitList.end(); iter++)
				{
					nodePath = iter->getNodePath();	// 因为场景中一个node可能包含在它的父节点中，所以说父Node和子Node都算碰撞点，所以输出到一个NodePath列表里。
					X = iter->getWorldIntersectPoint();
					if (minX > X.x())
					{
						minX = X.x();
					}
					if (maxX < X.x())
					{
						maxX = X.x();
					}
					if (minY > X.y())
					{
						minY = X.y();
					}
					if (maxY < X.y())
					{
						maxY = X.y();
					}
					if (minZ > X.z())
					{
						minZ = X.z();
					}
					if (maxZ < X.z())
					{
						maxZ = X.z();
					}
					
					for (osg::NodePath::iterator iterNode = nodePath.begin(); iterNode != nodePath.end(); iterNode++)
					{
						std::cout << "撞了: " << (*iterNode)->getName() << std::endl;
						if ((*iterNode)->getName() != "MyBox")
						{
							if (!pop)
							{
								pop = (*iterNode);
							}
							else
							{
								pop->setNodeMask(1);
							}
							(*iterNode)->setNodeMask(0x0); // 碰到墙就让它消失, 这样就能继续走
							pop = (*iterNode);
						}
					}
				}

			} // END 看看撞了谁

			// 移动到目的点
			{
				switch (point)
				{
				case LEFT:
				{
					NewPos = osg::Vec3d(maxX + 40, NewPos.y(), NewPos.z());
					sphere->toPosition(NewPos); // 球的半径是40，所以要往回走一点点
				}
				break;
				case RIGHT:
				{
					NewPos = osg::Vec3d(minX - 40, NewPos.y(), NewPos.z());
					sphere->toPosition(NewPos);
				}
				break;
				case FRONT:
				{
					NewPos = osg::Vec3d(NewPos.x(), minY - 40, NewPos.z());
					sphere->toPosition(NewPos);
				}
				break;
				case BACK:
				{
					NewPos = osg::Vec3d(NewPos.x(), minY + 40, NewPos.z());
					sphere->toPosition(NewPos);
				}
				break;
				case UP:
				{
					NewPos = osg::Vec3d(NewPos.x(), NewPos.y(), minZ - 40);
					sphere->toPosition(NewPos);
				}
				break;
				case DOWN:
				{
					NewPos = osg::Vec3d(NewPos.x(), NewPos.y(), maxZ + 40);
					sphere->toPosition(NewPos);
				}
				break;
				default:
					break;
				}
			}
		}
		else
		{
			sphere->toPosition(NewPos);
		}
	}

private:
	/* 移动的小球 */
	NodeMatrix* sphere;
	/* 当前位置 */
	osg::Vec3d position;
	/* 碰撞的物体 */
	osg::Node* box;
	/* 记录移动方向 */
	int point;
	/* POP */
	osg::Node* pop;
};

/* 画一个小球 */
osg::ref_ptr<osg::Geode> CreateSphere()
{
	osg::ref_ptr<osg::Geode> gnode = new osg::Geode();
	osg::ref_ptr<osg::ShapeDrawable> sd = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0, 0, 0), 40));
	gnode->addDrawable(sd.get());
	return gnode;
}

int main()
{
	// ExportBoxNode();

	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();
	osg::ref_ptr<osg::Group> gp = new osg::Group();
	osg::ref_ptr<NodeMatrix> nm = new NodeMatrix();

	osg::ref_ptr<osg::Node> node = CreateSphere();
	osg::ref_ptr<osg::Node> box = CreateBox();
	osg::ref_ptr<MoveSphereEventHandler> eh = new MoveSphereEventHandler(nm.get());


	nm->addsChild(node.get());
	nm->toPosition(osg::Vec3d(0, 0, 0));

	gp->setName("Root Group");
	box->setName("MyBox");
	node->setName("Sphere");
	nm->setName("NodeMatrixFirst");

	gp->addChild(nm.get());
	gp->addChild(box.get());

	// 设置碰撞场景
	eh->setNode(box.get());

	viewer->addEventHandler(eh);
	viewer->addEventHandler(new osgViewer::WindowSizeHandler); // 全屏/窗口模式切换 （F键）
	viewer->setSceneData(gp);
	viewer->setUpViewInWindow(100, 100, 1920, 1080);

	return viewer->run();
}